package com.yalantis.ucrop.view;


import com.yalantis.ucrop.callback.BitmapLoadCallback;
import com.yalantis.ucrop.model.ExifInfo;
import com.yalantis.ucrop.util.BitmapLoadUtils;
import com.yalantis.ucrop.util.FastBitmapDrawable;
import com.yalantis.ucrop.util.LogUtils;
import com.yalantis.ucrop.util.RectUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.PositionLayout;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.PixelMap;
import ohos.utils.net.Uri;

import java.util.Arrays;

/**
 * Created by Oleksii Shliama (https://github.com/shliama).
 * <p/>
 * This class provides base logic to setup the image, transform it with matrix (move, scale, rotate),
 * and methods to get current matrix state.
 */
public class TransformImageView extends PositionLayout implements Component.LayoutRefreshedListener, Component.DrawTask {

    PositionLayout.LayoutConfig layoutConfig = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT);

    private static final String TAG = "TransformImageView";

    private static final int RECT_CORNER_POINTS_COORDS = 8;
    private static final int RECT_CENTER_POINT_COORDS = 2;

    protected final float[] mCurrentImageCorners = new float[RECT_CORNER_POINTS_COORDS];
    protected final float[] mCurrentImageCenter = new float[RECT_CENTER_POINT_COORDS];

    protected Matrix mCurrentImageMatrix = new Matrix();
    protected int mThisWidth, mThisHeight;

    protected TransformImageListener mTransformImageListener;

    private float[] mInitialImageCorners;
    private float[] mInitialImageCenter;

    protected boolean mBitmapDecoded = false;
    protected boolean mBitmapLaidOut = false;

    private int mMaxBitmapSize = 0;

    private String mImageInputPath, mImageOutputPath;
    private ExifInfo mExifInfo;
    private final HiLogLabel hiLogLabel = new HiLogLabel(0, 0, TAG);
    public static final int MSCALE_X = 0;   //!< use with getValues/setValues
    public static final int MSKEW_X = 1;   //!< use with getValues/setValues
    public static final int MSKEW_Y = 3;   //!< use with getValues/setValues

    //添加一个全局变量PixelMapHolder用于传递图片，解决openharmony操作canvas时图像不变换的问题
    public PixelMapHolder mBitmapHolder;

    @Override
    public void onRefreshed(Component component) {
        if ((mBitmapDecoded && !mBitmapLaidOut)) {
            mThisWidth = component.getRight() - component.getLeft(); //风险等级3
            mThisHeight = component.getBottom() - component.getTop(); //风险等级3

            component.setLeft(getPaddingLeft());  //风险等级3
            component.setTop(getPaddingTop()); //风险等级3
            component.setRight(getWidth() - getPaddingRight()); //风险等级3
            component.setBottom(getHeight() - getPaddingBottom()); //风险等级3

            onImageLaidOut();
        }

    }

//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        super.onLayout(changed, left, top, right, bottom);
//        if (changed || (mBitmapDecoded && !mBitmapLaidOut)) {
//
//            left = getPaddingLeft();
//            top = getPaddingTop();
//            right = getWidth() - getPaddingRight();
//            bottom = getHeight() - getPaddingBottom();
//            mThisWidth = right - left;
//            mThisHeight = bottom - top;
//
//            onImageLaidOut();
//        }
//    }修改为上述代码，风险等级3

    /**
     * Interface for rotation and scale change notifying.
     */
    public interface TransformImageListener {

        void onLoadComplete();

        void onLoadFailure(Exception e);

        void onRotate(float currentAngle);

        void onScale(float currentScale);

    }

    public TransformImageView(Context context, AttrSet attrs, String s) {
        super(context, attrs, "0");
        System.out.println(s);
        init();
    }

    public int getMaxBitmapSize() {
        if (mMaxBitmapSize <= 0) {
            mMaxBitmapSize = BitmapLoadUtils.calculateMaxBitmapSize(getContext());
        }
        return mMaxBitmapSize;
    }

    //    @Override
    public void setPixelMap(final PixelMap bitmap) {
        //原：FastBitmapDrawable是一个Drawable，Drawbale可以被画在View里，所以直接set一个FastBitmapDrawable即可完成对图像的绘制
        //setImageElement(new FastBitmapDrawable(mContext, bitmap));
        //Drawable对标的是Element，但是由于功能缺陷，Element不支持自定义绘制，如果将FastBitmapDrawable继承Element则不能完成绘制任务
        //所以FastBitmapDrawable需要是一个Image，然而TransformImageView不能支持内置另一个Image，所以有必要将TransformImageView继承一个ComponentContainer
        //此处选择PositionLayout
        Component fastBitmapDrawable = new FastBitmapDrawable(mContext, bitmap);
        EventRunner main_runner = EventRunner.getMainEventRunner();
        EventHandler main_handler = new EventHandler(main_runner);
        main_handler.postTask(() -> addComponent(fastBitmapDrawable));
    }

    public String getImageInputPath() {
        return mImageInputPath;
    }

    public String getImageOutputPath() {
        return mImageOutputPath;
    }

    public ExifInfo getExifInfo() {
        return mExifInfo;
    }

    /**
     * setImageUri
     *
     * @param imageUri imageUri
     * @param outputUri outputUri
     */
    public void setImageUri(Uri imageUri, Uri outputUri) {
        int maxBitmapSize = getMaxBitmapSize();

        BitmapLoadUtils.decodeBitmapInBackground(getContext(), imageUri, outputUri, maxBitmapSize, maxBitmapSize,
                new BitmapLoadCallback() {
                    @Override
                    public void onBitmapLoaded(PixelMap bitmap, ExifInfo exifInfo, String imageInputPath, String imageOutputPath) {
                        mImageInputPath = imageInputPath;
                        mImageOutputPath = imageOutputPath;
                        mExifInfo = exifInfo;
                        mBitmapDecoded = true;

                        // 全局变量PixelMapHolder
                        mBitmapHolder = new PixelMapHolder(bitmap);

                        setPixelMap(bitmap);
                    }

                    @Override
                    public void onFailure(Exception bitmapWorkerException) {
                        if (mTransformImageListener != null) {
                            mTransformImageListener.onLoadFailure(bitmapWorkerException);
                        }
                    }
                });
    }

    /**
     * getCurrentScale
     *
     * @return - current image scale value.
     * [1.0f - for original image, 2.0f - for 200% scaled image, etc.]
     */
    public float getCurrentScale() {
        return getMatrixScale(mCurrentImageMatrix);
    }

    /**
     * getMatrixScale
     *
     * @param matrix matrix
     * @return getMatrixScale
     */
    public float getMatrixScale(Matrix matrix) {
        return (float) Math.sqrt(Math.pow(getMatrixValue(matrix, MSCALE_X), 2)
                + Math.pow(getMatrixValue(matrix, MSKEW_Y), 2));
    }

    /**
     * getCurrentAngle
     *
     * @return - current image rotation angle.
     */
    public float getCurrentAngle() {
        return getMatrixAngle(mCurrentImageMatrix);
    }

    /**
     * getMatrixAngle
     *
     * @param matrix matrix
     * @return getMatrixAngle
     */
    public float getMatrixAngle(Matrix matrix) {
        return (float) -(Math.atan2(getMatrixValue(matrix, MSKEW_X),
                getMatrixValue(matrix, MSCALE_X)) * (180 / Math.PI));
    }


    public void setImageMatrix(Matrix matrix) {
        addDrawTask((component, canvas) -> {
            canvas.save();
            canvas.setMatrix(matrix);
            canvas.drawPixelMapHolder(mBitmapHolder, 0, 0, new Paint());
            canvas.restore();
            float[] a = matrix.getData();
            LogUtils.LogInfo("qqqqqqqq:", "matrix" + Arrays.toString(a));
        });
        mCurrentImageMatrix.setMatrix(matrix);
        updateCurrentImagePoints();
    } // 风险等级∞，修改上述代码

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.setMatrix(mCurrentImageMatrix);

 // updateCurrentImagePoints();

    }//风险等级∞，修改上述代码


    public PixelMap getViewBitmap() {
        //原本此处采用Image的getImageElement(),为了适配PositionLayout，尝试使用getComponentAT()替代
        if (getComponentAt(0) == null || !(getComponentAt(0) instanceof FastBitmapDrawable)) {
            return null;
        } else {
            return ((FastBitmapDrawable) getComponentAt(0)).getBitmap();
        }
    }

    /**
     * This method translates current image.
     *
     * @param deltaX - horizontal shift
     * @param deltaY - vertical shift
     */
    public void postTranslate(float deltaX, float deltaY) {
        if (deltaX != 0 || deltaY != 0) {
            mCurrentImageMatrix.postTranslate(deltaX, deltaY);
            setImageMatrix(mCurrentImageMatrix);
            LogUtils.LogInfo("qqqqqqq:", "postTranslate to setMatrix");
        }
    }

    /**
     * This method scales current image.
     *
     * @param deltaScale - scale value
     * @param px         - scale center X
     * @param py         - scale center Y
     * @param type       type
     */
    public void postScale(float deltaScale, float px, float py,int type) {
        if (deltaScale != 0) {
            if (type == 1) {
                mCurrentImageMatrix.postScale(deltaScale, deltaScale, px, py);
                setImageMatrix(mCurrentImageMatrix);
                if (mTransformImageListener != null) {
                    mTransformImageListener.onScale(getMatrixScale(mCurrentImageMatrix));
                }
            } else {
                mCurrentImageMatrix.reset();
                setImageMatrix(mCurrentImageMatrix);
            }
        }
    }

    /**
     * This method rotates current image.
     *
     * @param deltaAngle - rotation angle
     * @param px         - rotation center X
     * @param py         - rotation center Y
     */
    public void postRotate(float deltaAngle, float px, float py) {
        if (deltaAngle != 0) {
            mCurrentImageMatrix.postRotate(deltaAngle, px, py);
            setImageMatrix(mCurrentImageMatrix);
            if (mTransformImageListener != null) {
                mTransformImageListener.onRotate(getMatrixAngle(mCurrentImageMatrix));
            }
        }
    }

    protected void init() {
//        setScaleType(ScaleType.MATRIX);
        this.setLayoutConfig(layoutConfig);
        this.setLayoutRefreshedListener(this);
    }
// 代码，没有ScaleType.MATRIX，风险等级2


    /**
     * When image is laid out {@link #mInitialImageCenter} and {@link #mInitialImageCenter}
     * must be set.
     */
    protected void onImageLaidOut() {
        //原本此处采用Image的getImageElement(),为了适配PositionLayout，尝试使用getComponentAT()替代
        final Component drawable = getComponentAt(0);
        if (drawable == null) {
            return;
        }

//        float w = drawable.getIntrinsicWidth();
//        float h = drawable.getIntrinsicHeight();
        //风险等级3 没有函数
        float w = mBitmapHolder.getPixelMap().getImageInfo().size.width;
        float h = mBitmapHolder.getPixelMap().getImageInfo().size.height;

        HiLog.debug(hiLogLabel, String.format("Image size: [%d:%d]", (int) w, (int) h));

        RectFloat initialImageRect = new RectFloat(0, 0, w, h);
        mInitialImageCorners = RectUtils.getCornersFromRect(initialImageRect);
        mInitialImageCenter = RectUtils.getCenterFromRect(initialImageRect);

        mBitmapLaidOut = true;

        if (mTransformImageListener != null) {
            mTransformImageListener.onLoadComplete();
        }
    }

    protected float getMatrixValue(Matrix matrix, int valueIndex) {
        float[] mMatrixValues = matrix.getData();
        return mMatrixValues[valueIndex];
    }

    /**
     * This method updates current image corners and center points that are stored in
     * {@link #mCurrentImageCorners} and {@link #mCurrentImageCenter} arrays.
     * Those are used for several calculations.
     */
    private void updateCurrentImagePoints() {
        mCurrentImageMatrix.mapPoints(mCurrentImageCorners, mInitialImageCorners);
        mCurrentImageMatrix.mapPoints(mCurrentImageCenter, mInitialImageCenter);
    }

}
